package transportServer

import (
	"fmt"
	config2 "gitee.com/jjawesomejj/awesome-util/config"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
	"gitee.com/jjawesomejj/awesome-util/ws"
	"github.com/gorilla/websocket"
	"github.com/net-byte/vtun/appConfig"
	"github.com/net-byte/vtun/common/config"
	"github.com/net-byte/vtun/common/netutil"
	"github.com/net-byte/vtun/common/unpacket"
	"github.com/net-byte/water"
	"log"
	"os/exec"
	"runtime"
	"strings"
)

var wsConn *websocket.Conn

func init() {
	if runtime.GOOS == "windows" {
		ruleName := "awesome-transport-vpn-accessor"
		checkCommand := commonhelper.Format("advfirewall firewall show rule name={}", ruleName)
		output, _ := exec.Command("cmd", "/C", checkCommand).CombinedOutput()
		if strings.Index(string(output), ruleName) == -1 {
			command := `netsh advfirewall firewall add rule name="{}" dir=in action=allow protocol=ANY localip=172.16.0.0/24`

			command = commonhelper.Format(command, ruleName)
			fmt.Println(command, "===============>")
			cmd := exec.Command("cmd", "/C", command)
			out, err := cmd.CombinedOutput()
			if err != nil {
				fmt.Println(out, "添加防火墙失败")
				fmt.Println(err)
			}
		}

	}
}

func getClient() ws.WebsocketClientJs {
	client := ws.WebsocketClientJs{}
	client.OnConnect(func(conn *websocket.Conn) {
		fmt.Println("连接到代理服务器")
		sid := appConfig.GetLocalSid()
		initMsg := InitMsg{
			Command: COMMAND_INIT,
			Sid:     sid,
		}
		conn.WriteJSON(initMsg)
		wsConn = conn
	})
	return client
}

func StartClient(iface *water.Interface, config config.Config) {
	log.Println("vtun ws local client started")
	client := getClient()
	client.OnMessage(func(msg string) {
		//下面开始解包
		sendToTunMsg := ClientMsgSendToTun{}
		fmt.Println("接受到新的包")
		err := commonhelper.JsonDecodeWithType(msg, &sendToTunMsg)
		if err != nil {
			fmt.Println("解包失败", err)
			return
		}
		buff := sendToTunMsg.Payload
		if sendToTunMsg.IsFinish {
			fmt.Println("接受到结束回环标记")
			//结束循环 将包对应的目标地址替换为访问的ip然后发送到虚拟网卡
			ip, err := appConfig.HostConfManager.GetLocalRequestIp(sendToTunMsg.SrcSid)
			if err != nil {
				fmt.Println("无效包")
				return
			}
			//下面开始替换报文头 将响应报文头里面的来源地址替换为远程host对应的ip地址
			newPacket := buff
			newPacket = unpacket.ChangeOrigin(buff, ip)
			newPacket = unpacket.ChangeDst(newPacket, appConfig.GetLocalIp())
			_, err = iface.Write(newPacket)
		} else {
			requestSid := sendToTunMsg.SrcSid
			ip, err := appConfig.HostConfManager.CreateRequestUserHost(requestSid)
			if err != nil {
				return
			}
			newPacket := buff
			newPacket = unpacket.ChangeOrigin(buff, ip)

			newPacket = unpacket.ChangeDst(newPacket, appConfig.GetLocalIp())
			_, err = iface.Write(newPacket)
			//header, err := unpacket.GetPacketHeader(buff)
			//if err == nil {
			//	//fmt.Println(header.Dst, "dst")
			//	//fmt.Println(header.Src, "src")
			//}
		}

	})
	fmt.Println(config2.GetConfigByKey("serverWsUrl").(string), "代理服务器地址")
	client.Connect(config2.GetConfigByKey("serverWsUrl").(string))
	go tunToTLS(config, iface, wsConn)
}

// tunToTLS sends packets from tun to tls
func tunToTLS(config config.Config, iface *water.Interface, ws *websocket.Conn) {
	packet := make([]byte, config.BufferSize)
	for {
		n, err := iface.Read(packet)
		//fmt.Println("readMessage")
		if err != nil {
			netutil.PrintErr(err, config.Verbose)
			break
		}
		header, err := unpacket.GetPacketHeader(packet[:n])
		if err != nil {
			continue
		}
		//fmt.Println("接受到目标地址的报文:" + header.Dst.String())
		host, err := appConfig.HostConfManager.GetHost(header.Dst.String())
		//fmt.Println(header.Dst.String())
		//没有找到对应的ip地址
		if err != nil {
			continue
		}
		fmt.Println("下面开始发送")
		isFinish := appConfig.HostConfManager.CheckIsLocalRequestIp(host)
		//下面开始封包
		msg := TransportMsg{
			Command:   COMMAND_TRANSPORT,
			Payload:   packet[:n],
			TargetSid: appConfig.HostConfManager.ResolveSidByHost(host),
			IsFinish:  isFinish,
		}
		//fmt.Println(header.Src.String() != "172.16.0.10", "结束回环标记"+timeHelper.Now())
		err = ws.WriteJSON(msg)
		if err != nil {
			fmt.Println(err, "发送数据到转发服务器失败")
			continue
		}
		//fmt.Println("成功发送到转发服务器:" + timeHelper.Now())
	}
}
